package org.rcgwt.client.ui.grid.internal;

/**
 * Element for Int Interval with start and size (count)
 * 
 * @author Matthieu ROBERT
 * 
 */
public class IntRange implements Comparable<IntRange>, Cloneable {

    static final IntIterator EMPTY_INT_ITERATOR = new IntIterator() {

        @Override
        public int next() {
            return -1;
        }

        @Override
        public boolean hasNext() {
            return false;
        }
    };

    private int start = -1;

    private int count = 0;

    private int lastIndex;

    public static IntRange createIntRange(int start, int lastIndex) {
        IntRange res = new IntRange(start, 1);
        res.setLastIndex(lastIndex);
        return res;
    }

    public IntRange(int start, int count) {
        this.start = start;
        setCount(count);

    }

    public int getFirstIndex() {
        return start;
    }

    public int getLastIndex() {
        return lastIndex;
    }

    public void setLastIndex(int lastIndex) {
        if (lastIndex < start) {
            throw new IllegalArgumentException("last index < start");
        }
        this.lastIndex = lastIndex;
        setCount(lastIndex - start + 1);
    }

    public void setStartIndex(int start) {
        this.start = start;

        // Define Count, last Index reste le même
        setCount(lastIndex - start + 1);
    }

    public int size() {
        return count;
    }

    public void setCount(int count) {
        if (count < 1) {
            throw new IllegalArgumentException("Count < 1");
        }
        this.count = count;
        this.lastIndex = start + count - 1;
    }

    public boolean contains(int index) {
        return (index >= start) && (index <= lastIndex);
    }

    public boolean contains(IntRange range) {
        return (range.start >= start) && (range.getLastIndex() <= lastIndex);
    }

    public IntIterator iterator() {
        return new IntIteratorDefault(this);
    }

    private static class IntIteratorDefault implements IntIterator {

        private int start;

        private int size;

        public IntIteratorDefault(IntRange range) {
            this.start = range.start;
            this.size = start + range.count;
        }

        public int next() {
            return start++;
        }

        public boolean hasNext() {
            return start < size;
        }
    }

    public IntRange intersect(IntRange range) {
        IntRange res = null;

        if (range.contains(this)) {
            return this.clone();
        }
        // {0,1}^{4,5} => {} | {7,8}^{4,5} => {}
        if ((range.lastIndex < this.start) || (range.start > this.lastIndex)) {
            return null;
        } else
        // {0,1,2}^{2,3,4} => {2}
        if ((range.lastIndex >= this.start) && (range.start <= this.start)) {
            res = IntRange.createIntRange(this.start, range.lastIndex);
        } else
        // {3,4}^{2,3,4} => {3,4}
        if ((range.start >= this.start) && (range.lastIndex <= this.lastIndex)) {
            res = IntRange.createIntRange(range.start, range.lastIndex);
        } else
        // {3,4,5}^{2,3,4} => {3,4}
        if ((range.start >= this.start) && (range.start <= this.lastIndex)
                && (range.getLastIndex() >= this.getLastIndex())) {
            res = IntRange.createIntRange(range.start, this.lastIndex);
        }

        return res;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof IntRange) {
            IntRange otherRange = (IntRange) obj;
            return (otherRange.start == this.start)
                    && (otherRange.count == this.count);
        }
        return false;
    }

    @Override
    public int compareTo(IntRange o) {
        return this.start - o.start;
    }

    public int[] toArray() {
        int[] res = new int[size()];
        int index = start;
        for (int i = 0; i < res.length; i++) {
            res[i] = index;
            index++;
        }

        return res;
    }

    @Override
    public String toString() {
        return "(" + start + "," + count + ")";
    }

    public IntRange clone() {
        return new IntRange(start, count);
    }
}
